package com.geovis.emergency.spd.biz.pc.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.geovis.common.auth.util.AuthUtil;
import com.geovis.common.core.exception.BizException;
import com.geovis.emergency.spd.biz.pc.mapper.PcDrillPlanTaskMapper;
import com.geovis.emergency.spd.biz.pc.service.*;
import com.geovis.emergency.spd.biz.system.service.ISystemFileBusinessService;
import com.geovis.emergency.spd.biz.system.service.ISystemFileService;
import com.geovis.emergency.spd.cache.DictCache;
import com.geovis.emergency.spd.entity.mobile.pojo.vo.DrillPlanTaskMobileDetailVO;
import com.geovis.emergency.spd.entity.mobile.pojo.vo.DrillPlanTaskMobileFeedbackVO;
import com.geovis.emergency.spd.entity.mobile.pojo.vo.DrillPlanTaskMobileVO;
import com.geovis.emergency.spd.entity.pc.entity.*;
import com.geovis.emergency.spd.entity.pc.pojo.constant.PcDisasterConstant;
import com.geovis.emergency.spd.entity.pc.pojo.constant.PcMessageConstant;
import com.geovis.emergency.spd.entity.pc.pojo.dto.PcDrillPlanTaskApprovalDTO;
import com.geovis.emergency.spd.entity.pc.pojo.enums.StatusEnum;
import com.geovis.emergency.spd.entity.pc.pojo.enums.TaskStatusEnum;
import com.geovis.emergency.spd.entity.pc.pojo.vo.DrillPlanTaskVO;
import com.geovis.emergency.spd.entity.pc.pojo.vo.TaskTimeStatisticsVO;
import com.geovis.emergency.spd.entity.system.constant.SystemFileBusinessConstant;
import com.geovis.emergency.spd.entity.system.entity.SystemFile;
import com.geovis.emergency.spd.entity.system.entity.SystemFileBusiness;
import com.geovis.emergency.spd.entity.system.pojo.dto.SystemFileQueryDTO;
import com.geovis.emergency.spd.util.MsgUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.Date;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * <p>
 * 应急预案指挥模块-演练工作方案任务表 服务实现类
 * </p>
 *
 * @author Lonsho
 * @since 2022-06-08
 */
@Service
@RequiredArgsConstructor
@Slf4j
public class PcDrillPlanTaskServiceImpl extends ServiceImpl<PcDrillPlanTaskMapper, PcDrillPlanTask> implements IPcDrillPlanTaskService {

    private final IPcDisasterEventService pcDisasterEventService;
    private final ISystemFileService systemFileService;
    private final ISystemFileBusinessService systemFileBusinessService;
    private final IPcDrillPlanTaskApprovalService pcDrillPlanTaskApprovalService;
    private final IPcDrillPlanTaskStatisticsService pcDrillPlanTaskStatisticsService;
    private final IPcDrillPlanService pcDrillPlanService;
    private final IPcDrillPlanDetailService pcDrillPlanDetailService;


    private final IPcDrillDisasterEventService pcDrillDisasterEventService;
    @Override
    public DrillPlanTaskMobileDetailVO detail(String taskId) {
        PcDrillPlanDetail task = pcDrillPlanDetailService.getById(taskId);
        if(task==null){
            return null;
        }
        DrillPlanTaskMobileVO covert = covert(taskId, DateUtil.date(), DateUtil.yesterday());
        DrillPlanTaskMobileDetailVO vo = new DrillPlanTaskMobileDetailVO();
        BeanUtil.copyProperties(covert,vo);
        vo.setId(task.getId());
        if (StrUtil.isNotBlank(task.getPcDrillDisasterEventId())) {
            PcDrillDisasterEvent pcDrillDisasterEvent = pcDrillDisasterEventService.getById(task.getPcDrillDisasterEventId());
            if (ObjectUtil.isNotNull(pcDrillDisasterEvent)) {
                vo.setTitle(pcDrillDisasterEvent.getTitle());
            }
        }
        PcDrillPlanTask planTask = baseMapper.selectByPlanId(taskId);
        if(planTask!=null){
            vo.setTaskFeedback(planTask.getContent());
            SystemFileQueryDTO systemFileQueryDTO = new SystemFileQueryDTO();
            systemFileQueryDTO.setRelatedId(planTask.getId());
            systemFileQueryDTO.setType(SystemFileBusinessConstant.TYPE_MOBILE_TASK_FEEDBACK);
            vo.setFileDTOS(systemFileService.getList(systemFileQueryDTO));
            vo.setTaskStatistics(pcDrillPlanTaskStatisticsService.getByTaskId(planTask.getId()));
        }
        return vo;
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public PcDrillPlanDetail feedback(DrillPlanTaskMobileFeedbackVO vo,String userId) {
        PcDrillPlanDetail planDetail = pcDrillPlanDetailService.getById(vo.getTaskId());
        if(planDetail==null){
            throw new BizException("无法获取到方案信息,请重新尝试！");
        }
        PcDrillPlanTask planTask =  baseMapper.selectByPlanId(vo.getTaskId());
        if(planTask!=null){
            //之前提交记录存在，更新提交提记录
            planTask.setContent(vo.getTaskFeedback());
            planTask.setStatus(TaskStatusEnum.WAIT_APPROVAL.getCode());
            baseMapper.updateById(planTask);
        }else{
            //之前提交记录不存在,新增提交记录
            planTask = new PcDrillPlanTask();
            planTask.setPcDrillId(planDetail.getPcDrillId());
            planTask.setPcDrillPlanId(planDetail.getPcDrillPlanId());
            planTask.setPcDrillPlanDetailId(planDetail.getId());
            planTask.setPcDrillDisasterId(planDetail.getPcDrillDisasterId());
            planTask.setPcDrillDisasterEventId(planDetail.getPcDrillDisasterEventId());
            planTask.setPrincipalId(userId);
            planTask.setPrincipalName(AuthUtil.getCurrUser().getRealName());
            planTask.setContent(vo.getTaskFeedback());
            planTask.setStatus(TaskStatusEnum.WAIT_APPROVAL.getCode());
            baseMapper.insert(planTask);
        }

        //保存附件
        if (CollUtil.isNotEmpty(vo.getFileDTOS())) {
            PcDrillPlanTask finalPlanTask = planTask;
            systemFileBusinessService.remove(
                    Wrappers.lambdaQuery(SystemFileBusiness.class)
                            .eq(SystemFileBusiness::getType,SystemFileBusinessConstant.TYPE_MOBILE_TASK_FEEDBACK)
                            .eq(SystemFileBusiness::getRelatedId,finalPlanTask.getId())
            );
            Set<SystemFileBusiness> fileBusinessSet = CollUtil.set(false);
            vo.getFileDTOS().forEach(file ->
                    fileBusinessSet.add(new SystemFileBusiness(file.getId(), SystemFileBusinessConstant.TYPE_MOBILE_TASK_FEEDBACK, finalPlanTask.getId())));
            systemFileBusinessService.saveBatch(fileBusinessSet);
        }
        //保存统计
        pcDrillPlanTaskStatisticsService.save(planTask.getId(),vo.getTaskStatistics());
        //保存记录
        PcDrillPlanTaskApproval pcDrillPlanTaskApproval = new PcDrillPlanTaskApproval();
        pcDrillPlanTaskApproval.setPcDrillId(planTask.getPcDrillId());
        pcDrillPlanTaskApproval.setPcDrillPlanId(planTask.getPcDrillPlanId());
        pcDrillPlanTaskApproval.setPcDrillDisasterId(planTask.getPcDrillDisasterId());
        pcDrillPlanTaskApproval.setPcDrillDisasterEventId(planTask.getPcDrillDisasterEventId());
        pcDrillPlanTaskApproval.setPcDrillPlanTaskId(planTask.getId());
        pcDrillPlanTaskApproval.setPcDrillPlanDetailId(planTask.getPcDrillPlanDetailId());
        pcDrillPlanTaskApproval.setContent("提交审核");
        pcDrillPlanTaskApproval.setStatus(TaskStatusEnum.WAIT_APPROVAL.getCode());
        pcDrillPlanTaskApproval.setAuditId(userId);
        pcDrillPlanTaskApproval.setApprovalTime(LocalDateTime.now());
        pcDrillPlanTaskApproval.setIsDeleted(StatusEnum.FALSE.getCode());
        pcDrillPlanTaskApprovalService.save(pcDrillPlanTaskApproval);

        return planDetail;

    }
    @Override
    public DrillPlanTaskVO getTaskFeedback(String planId) {
        LambdaQueryWrapper<PcDrillPlanTask> queryWrapper = Wrappers.lambdaQuery();
        queryWrapper.eq(PcDrillPlanTask::getPcDrillPlanDetailId, planId);
        queryWrapper.orderByDesc(PcDrillPlanTask::getCreateTime);
        queryWrapper.last("limit 1");

        PcDrillPlanTask pcDrillPlanTask = baseMapper.selectOne(queryWrapper);
        if (ObjectUtil.isNotNull(pcDrillPlanTask)){
            SystemFileQueryDTO systemFileQueryDTO = new SystemFileQueryDTO();
            systemFileQueryDTO.setRelatedId(pcDrillPlanTask.getId());
            systemFileQueryDTO.setType(SystemFileBusinessConstant.TYPE_MOBILE_TASK_FEEDBACK);
            List<SystemFile> fileList = systemFileService.getList(systemFileQueryDTO).stream().map(item -> BeanUtil.toBean(item, SystemFile.class)).collect(Collectors.toList());
            DrillPlanTaskVO drillPlanTaskVO = BeanUtil.toBean(pcDrillPlanTask, DrillPlanTaskVO.class);
            drillPlanTaskVO.setFileList(fileList);
            drillPlanTaskVO.setTaskStatistics(pcDrillPlanTaskStatisticsService.getByTaskId(pcDrillPlanTask.getId()));

            //查询退审记录
            drillPlanTaskVO.setRejectList(
                    pcDrillPlanTaskApprovalService.list(
                            Wrappers.lambdaQuery(PcDrillPlanTaskApproval.class)
                                    .eq(PcDrillPlanTaskApproval::getPcDrillPlanTaskId,pcDrillPlanTask.getId())
                                    .eq(PcDrillPlanTaskApproval::getStatus,TaskStatusEnum.FAIL.getCode())
                                    .orderByDesc(PcDrillPlanTaskApproval::getCreateTime)
                    )
            );
            return drillPlanTaskVO;
        }

        return null;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void approve(PcDrillPlanTaskApprovalDTO approvalDTO) {
        PcDrillPlanTask pcDrillPlanTask = baseMapper.selectById(approvalDTO.getTaskId());
        Assert.notNull(pcDrillPlanTask,"任务反馈内容不存在");
        PcDrillPlan pcDrillPlan = pcDrillPlanService.getById(pcDrillPlanTask.getPcDrillPlanId());
        Assert.notNull(pcDrillPlanTask,"方案内容不存在");
        PcDrillPlanDetail pcDrillPlanDetail = pcDrillPlanDetailService.getById(pcDrillPlanTask.getPcDrillPlanDetailId());
        Assert.notNull(pcDrillPlanTask,"方案内容详情不存在");
        if (approvalDTO.getPass()){
            //通过审核
            pcDrillPlanTask.setStatus(TaskStatusEnum.PASS.getCode());
            approvalDTO.setRejectReason(TaskStatusEnum.PASS.getMsg());
        }else {
            //退审
            pcDrillPlanTask.setStatus(TaskStatusEnum.FAIL.getCode());
            Assert.notBlank(approvalDTO.getRejectReason(),"退审原因不能为空");
        }
        baseMapper.updateById(pcDrillPlanTask);
        //保存审核记录
        PcDrillPlanTaskApproval pcDrillPlanApproval = new PcDrillPlanTaskApproval()
                .setPcDrillId(pcDrillPlanTask.getPcDrillId())
                .setContent(approvalDTO.getRejectReason())
                .setStatus(pcDrillPlanTask.getStatus())
                .setPcDrillPlanId(pcDrillPlan.getId())
                .setPcDrillPlanDetailId(pcDrillPlanDetail.getId())
                .setPcDrillDisasterId(pcDrillPlanTask.getPcDrillDisasterId())
                .setPcDrillDisasterEventId(pcDrillPlanTask.getPcDrillDisasterEventId())
                .setPcDrillPlanTaskId(pcDrillPlanTask.getId())
                .setAuditId(AuthUtil.getCurrentUserId())
                .setApprovalTime(LocalDateTime.now());
        pcDrillPlanTaskApprovalService.save(pcDrillPlanApproval);

        if (approvalDTO.getPass()){
            //方案审核时间，即方案下发时间
            LocalDateTime auditTime = pcDrillPlan.getAuditTime();
            //任务反馈审核时间
            LocalDateTime approvalTime = pcDrillPlanApproval.getApprovalTime();
            //相差的分钟数
            long timeDiff = DateUtil.between(DateUtil.date(auditTime), DateUtil.date(approvalTime), DateUnit.MINUTE);
            //任务反馈审核时间 - 方案下发时间 = 任务用时
            pcDrillPlanDetail.setSpendTime((int) timeDiff);
            //更新任务用时
            pcDrillPlanDetailService.updateById(pcDrillPlanDetail);
            MsgUtil.pushMsgByUser(PcMessageConstant.TYPE_PLAN_EXE_AUDIT_PASS,"反馈审核成功","您提交的反馈内容【已过审】",pcDrillPlanTask.getPcDrillId(),pcDrillPlanTask.getId(),pcDrillPlanDetail.getPrincipalId());
        }else {
            MsgUtil.pushMsgByUser(PcMessageConstant.TYPE_PLAN_EXE_AUDIT_BACK,"反馈审核不通过","您提交的反馈内容【已退审】",pcDrillPlanTask.getPcDrillId(),pcDrillPlanTask.getId(),pcDrillPlanDetail.getPrincipalId());
        }
    }

    @Override
    public List<TaskTimeStatisticsVO> selectTimeStatistics(String drillId, String pcDrillDisasterId) {
        return baseMapper.selectTimeStatistics(drillId,pcDrillDisasterId);
    }

    /**
     * 将实体类转换成对应VO类
     * @param taskId 方案id
     * @return
     */
    private DrillPlanTaskMobileVO covert(String taskId, Date today,Date yesterday){
        PcDrillPlanDetail pcDrillPlanTask = pcDrillPlanDetailService.getById(taskId);
        DrillPlanTaskMobileVO vo = new DrillPlanTaskMobileVO();
        vo.setTaskId(taskId);
        vo.setStatus(pcDrillPlanTask.getStatus());
        vo.setContent(pcDrillPlanTask.getContent());
        Date createTime = Date.from(pcDrillPlanTask.getCreateTime().atZone(ZoneId.systemDefault()).toInstant());
        vo.setShowTime(DateUtil.format(createTime,"HH:mm"));
        if(DateUtil.isSameDay(today,createTime)){
            vo.setTimePeriod("今天");
        }else if(DateUtil.isSameDay(yesterday,createTime)){
            vo.setTimePeriod("昨天");
        }else{
            vo.setTimePeriod(DateUtil.formatDate(createTime));
        }
        PcDisasterEvent disasterEvent = pcDisasterEventService.getById(pcDrillPlanTask.getPcDrillDisasterEventId());
        if(disasterEvent!=null){
            vo.setTitle(disasterEvent.getTitle());
            String dictValue = DictCache.getDictValue(PcDisasterConstant.DISASTER_TYPE, disasterEvent.getType());
            vo.setDisasterType(dictValue);
        }
        return vo;
    }
}
